#include<iostream>
#include<string>
#include <string.h>
#include<pthread.h>
#include <netinet/in.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include"Init.hpp"
#include"ThreadPool.hpp"
#include"Daemon.hpp"
#include"Task.hpp"

const int backlog = 10; // 一般不要设置的太大
const std::string defaultip="0.0.0.0";
const uint16_t defaultport=8888;
const int defaultfd = -1;
const int threadnums=5;
pthread_mutex_t mutex;
enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError,
};
class TcpServer;
class ThreadData
{
public:
    ThreadData(int sockfd,std::string clientip,uint16_t clientport,TcpServer* tcp)
    :sockfd_(sockfd),clientip_(clientip),clientport_(clientport),tcp_(tcp)
    {

    }

    int sockfd_;
    const std::string clientip_;
    const uint16_t clientport_;
    TcpServer* tcp_;

};
class TcpServer
{
public:
    TcpServer(const uint16_t port=defaultport,const std::string ip=defaultip)
    :port_(port),ip_(ip),listensock_(defaultfd)
    {
        pthread_mutex_init(&mutex, NULL);
    }
    void InitServer()
    {
        //1.创建套接字
        listensock_=socket(AF_INET, SOCK_STREAM,0);
        if(listensock_<0)
        {
           lg(Fatal, "create socket, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info,"create socket success, listensock_: %d", listensock_);
        //?
        int opt = 1;
        setsockopt(listensock_, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt)); // 防止偶发性的服务器无法进行立即重启(tcp协议的时候再说)
        
        struct sockaddr_in local;
        bzero(&local,0);
        local.sin_family=AF_INET;
        local.sin_port=htons(port_);
        inet_aton(ip_.c_str(),&local.sin_addr);

        //2.绑定
        socklen_t len=sizeof(local);
        if(bind(listensock_,(const struct sockaddr*)&local,len)<0)
        {
            lg(Fatal, "BindError: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info,"bind success, listensock_: %d", listensock_);
        
        //3.等待监听
        // Tcp是面向连接的，服务器一般是比较“被动的”，服务器一直处于一种，一直在等待连接到来的状态
        if(listen(listensock_,backlog)<0)
        {
            lg(Fatal, "listen errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }
        lg(Info,"listen success, listensock_: %d", listensock_);
    }
    static void* Routinue(void*args)
    {
        ThreadData*tp=static_cast<ThreadData*>(args);
        pthread_mutex_lock(&mutex);
        tp->tcp_-> Service(tp->sockfd_,tp->clientip_,tp->clientport_);
        pthread_mutex_unlock(&mutex);
        delete tp;
        return nullptr;
    }
    void Start()
    {
         //Daemon();
        //ThreadPool<Task>::GetInstance()->Start();
        lg(Info,"tcpServer is running....");
        for(;;)
        {
            struct sockaddr_in client;
            socklen_t len=sizeof(client);
            int sockfd=accept(listensock_,(sockaddr*)&client,&len);
            if(sockfd<0)
            {
                lg(Fatal, "accept errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            uint16_t clientport=ntohs(client.sin_port);
            char clientip[20];
           inet_ntop(AF_INET,&client.sin_addr,clientip,sizeof(clientip));
           // 2. 根据新连接来进行通信
            lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);

        //version 1 单进程版
            // Service(sockfd, clientip, clientport);
            // close(sockfd);

        //version 2 多进程版
        // pid_t pid;
        // pid=fork();
        // if(pid==0)
        // {
        //     //child
        //     close(listensock_);
        //     if(fork()>0)
        //     {
        //         exit(1);
        //     }
        //     Service(sockfd, clientip, clientport);
        //     close(sockfd);
        //     exit(0);
        // }
        // close(sockfd);
        // // father
        // pid_t rid = waitpid(pid, nullptr, 0);
        // (void)rid;

        //version 3 多线程版
        // ThreadData* tp=new ThreadData(sockfd,clientip,clientport,this);
        // pthread_t pid;
        // for(size_t i=1;i<=threadnums;i++)
        // {
        //     pthread_create(&pid,0,Routinue,tp);
        // }
        //version 4 线程池版
        Task t(sockfd, clientip, clientport);
        ThreadPool<Task>::GetInstance()->Push(t);
        ThreadPool<Task>::GetInstance()->Start();
        }
    }
   void Service(int sockfd,const std::string clientip,const uint16_t clientport)
    {
        char buff[4096];
        while(true)
        {
            ssize_t n=read(sockfd,buff,sizeof(buff));
            if(n<0)
            {
                lg(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);
                break;
            }
            else if(n==0)
            {
                lg(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
                break;
            }else{
                buff[n]=0;
                std::cout<<"Client say#"<<buff<<std::endl;
                std::string echo_string="Tcpserver echo#";
                echo_string+=buff;
                write(sockfd,echo_string.c_str(),echo_string.size());
            }
        }
    }
      ~TcpServer() {}
private:
    int listensock_;
    uint16_t port_;
    std::string ip_;
};